using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.IO.IsolatedStorage;
using System.Runtime.Serialization;
#if WINDOWS
using System.Runtime.Serialization.Formatters.Binary;
#endif

#if XBOX
using EasyStorage;
#endif

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using GameStateManagement;
using Frogger_Input;

// ****************************************************************************** //
//        This component handle all the pause menu entries and functions          //
// ****************************************************************************** //

namespace Frogger_Game
{

    public class Pause_Menu : Microsoft.Xna.Framework.DrawableGameComponent
    {
        public Pause_Menu(Game game)
            : base(game)
        {
        }

          #region Fields

        public Texture2D background;
        SpriteBatch spriteBatch;
        SpriteFont font;
        MessageBoxScreen messageBox;
        SoundData sound;
        GameTimer t;
#if XBOX
        IAsyncSaveDevice saveDevice;
        SharedSaveDevice sharedSaveDevice;
#endif

        List<MenuEntry> menuEntries;
        List<MenuEntry> menuArrows;
        int selectedEntry = 0;
        int selectedArrow = 0;

        MenuEntry backToMainMenu;
        MenuEntry saveEntry;
        MenuEntry loadEntry;
        MenuEntry minMusicVolume;
        MenuEntry maxMusicVolume;
        MenuEntry minEffectsVolume;
        MenuEntry maxEffectsVolume;

        InputState input;
        InputButtons ib;

        MenuEntry musicVolumeMenuEntry;
        MenuEntry effectsVolumeMenuEntry;

        #endregion


        /// <summary>
        /// Initialize all non-graphics content
        /// </summary>
        public override void Initialize()
        {
            font = Game.Content.Load<SpriteFont>("menufont");
 
            menuEntries = new List<MenuEntry>();
            menuArrows = new List<MenuEntry>();
            input = (InputState)Game.Services.GetService(typeof(InputState));
            ib = (InputButtons)Game.Services.GetService(typeof(InputButtons));
           
            //add menu entries
            musicVolumeMenuEntry = new MenuEntry(string.Empty, font);
            effectsVolumeMenuEntry = new MenuEntry(string.Empty, font);
            backToMainMenu = new MenuEntry("Back to Main Menu", font);
            MenuEntry back = new MenuEntry("Back",font);
            saveEntry = new MenuEntry("Save", font);
            loadEntry = new MenuEntry("Load", font);
            minMusicVolume = new MenuEntry("-", font);
            maxMusicVolume = new MenuEntry("+", font);
            minEffectsVolume = new MenuEntry("-", font);
            maxEffectsVolume = new MenuEntry("+", font);

            // Hook up menu event handlers.
            minMusicVolume.Selected += MusicVolumeDownEntrySelected;
            maxMusicVolume.Selected += MusicVolumeUpEntrySelected;
            minEffectsVolume.Selected += EffectsVolumeDownEntrySelected;
            maxEffectsVolume.Selected += EffectsVolumeUpEntrySelected;
            back.Selected += BackSelected;
            backToMainMenu.Selected += BackToMainMenuSelected;
            saveEntry.Selected += SaveEntrySelected;
            loadEntry.Selected += LoadEntrySelected;

            // Add entries to the menu.

            menuEntries.Add(back);
            menuEntries.Add(saveEntry);
            menuEntries.Add(loadEntry);
            menuEntries.Add(musicVolumeMenuEntry);
            menuEntries.Add(effectsVolumeMenuEntry);
            menuEntries.Add(backToMainMenu);
            menuArrows.Add(minMusicVolume);
            menuArrows.Add(maxMusicVolume);
            menuArrows.Add(minEffectsVolume);
            menuArrows.Add(maxEffectsVolume);

            SetMenuEntryText();

            sound = (SoundData)Game.Services.GetService(typeof(SoundData));
            t = (GameTimer)Game.Services.GetService(typeof(GameTimer));
            sound.SetMusicVolume(Game1.musicVolume);
            sound.SetEffectsVolume(Game1.effectsVolume);
            sound.PlaySound(sound.ThemeInstance);


#if XBOX

            // we can set our supported languages explicitly or we can allow the
            // game to support all the languages. the first language given will
            // be the default if the current language is not one of the supported
            // languages. this only affects the text found in message boxes shown
            // by EasyStorage and does not have any affect on the rest of the game.
            EasyStorageSettings.SetSupportedLanguages(Language.English, Language.Italian);

            // create and add our SaveDevice
            sharedSaveDevice = new SharedSaveDevice();
            Game.Components.Add(sharedSaveDevice);

            // make sure we hold on to the device
            saveDevice = sharedSaveDevice;

            // hook two event handlers to force the user to choose a new device if they cancel the
            // device selector or if they disconnect the storage device after selecting it
            sharedSaveDevice.DeviceSelectorCanceled += (s, e) => e.Response = SaveDeviceEventResponse.Force;
            sharedSaveDevice.DeviceDisconnected += (s, e) => e.Response = SaveDeviceEventResponse.Force;

            // prompt for a device on the first Update we can
            sharedSaveDevice.PromptForDevice();

            saveDevice.SaveCompleted += new SaveCompletedEventHandler(saveDevice_SaveCompleted);
#endif


            base.Initialize();
        }

        #region Handle Input

       
#if XBOX
        void saveDevice_SaveCompleted(object sender, FileActionCompletedEventArgs args)
        {
            // just write some debug output for our verification
            Console.WriteLine("SaveCompleted!");
        }

#endif

        void SaveEntrySelected(object sender, PlayerIndexEventArgs e)
        {
            #if WINDOWS
            using (IsolatedStorageFile IS = IsolatedStorageFile.GetUserStoreForDomain())
            {
                using (IsolatedStorageFileStream stream = IS.OpenFile("savegame.sav", FileMode.Create))
                {
                    BinaryFormatter binformat = new BinaryFormatter();
                    binformat.Serialize(stream, GameState.game_state);
                }
            }
#elif XBOX     
            // make sure the device is ready
            if (saveDevice.IsReady)
            {
                // save a file asynchronously. this will trigger IsBusy to return true
                // for the duration of the save process.
                saveDevice.SaveAsync(
                    "FroggerSaveGame",
                    "savegame.sav",
                    stream =>
                    {
                        using (StreamWriter writer = new StreamWriter(stream))
                        {
                            writer.WriteLine(GameState.game_state.count_win);
                            writer.WriteLine(GameState.game_state.level);
                            writer.WriteLine(GameState.game_state.Life);
                            writer.WriteLine(GameState.game_state.river_position);
                            writer.WriteLine(GameState.game_state.time_counter);
                            writer.WriteLine(GameState.game_state.winbox_check[0]);
                            writer.WriteLine(GameState.game_state.winbox_check[1]);
                            writer.WriteLine(GameState.game_state.winbox_check[2]);
                            writer.WriteLine(GameState.game_state.winbox_check[3]);
                            writer.WriteLine(GameState.game_state.winbox_check[4]);
                        }
                    });
            }
#endif
            saveEntry.Text = "SAVED DONE!";
        }


        void LoadEntrySelected(object sender, PlayerIndexEventArgs e)
        {
    #if WINDOWS
            using (IsolatedStorageFile IS = IsolatedStorageFile.GetUserStoreForDomain())
            {
                if (IS.FileExists("savegame.sav"))
                {
                    using (IsolatedStorageFileStream stream = IS.OpenFile("savegame.sav", FileMode.Open))
                    {
                        t.timer = 0;
                        BinaryFormatter binformat = new BinaryFormatter();
                        FrogSimulation.reset_state();
                        CarsTypes.reset_state();
                        RiverTypes.reset_state();
                        GameState.reset_state();
                        GameState.game_state = (GameState.GameState)binformat.Deserialize(stream);
                        WinLogic.check_level();
                    }
                BackSelected(sender, e);
                }
                else
                {
                    loadEntry.Text = "NO FILE TO LOAD...";
                }
            }
#elif XBOX
            if (saveDevice.FileExists("FroggerSaveGame","savegame.sav"))
            {
                saveDevice.Load(
                    "FroggerSaveGame",
                    "savegame.sav",
                    stream =>
                    {
                        using (StreamReader reader = new StreamReader(stream))
                        {
                            t.timer = 0;
                            FrogSimulation.reset_state();
                            CarsTypes.reset_state();
                            RiverTypes.reset_state();
                            GameState.reset_state();
                            GameState.game_state.count_win = int.Parse(reader.ReadLine());
                            GameState.game_state.level = int.Parse(reader.ReadLine());
                            GameState.game_state.Life = int.Parse(reader.ReadLine());
                            GameState.game_state.river_position = bool.Parse(reader.ReadLine());
                            GameState.game_state.time_counter = float.Parse(reader.ReadLine());
                            GameState.game_state.winbox_check[0] = bool.Parse(reader.ReadLine());
                            GameState.game_state.winbox_check[1] = bool.Parse(reader.ReadLine());
                            GameState.game_state.winbox_check[2] = bool.Parse(reader.ReadLine());
                            GameState.game_state.winbox_check[3] = bool.Parse(reader.ReadLine());
                            GameState.game_state.winbox_check[4] = bool.Parse(reader.ReadLine());
                            WinLogic.check_level();
            
                        }
                    });
               BackSelected(sender, e);
            }
            else
            {
                    loadEntry.Text = "NO FILE TO LOAD...";
            }
            //SetMenuEntryText();

#endif

        }

        /// <summary>
        /// Event handler for when the Back menu entry is selected.
        /// </summary>
        void BackSelected(object sender, PlayerIndexEventArgs e)
        {
            Game1.isPaused = false;
            sound.StopSound(sound.ThemeInstance);
            this.Dispose();
#if XBOX
            Game.Components.Remove(sharedSaveDevice);
#endif
            Game.Components.Remove(this);

        }

        void BackToMainMenuSelected(object sender, PlayerIndexEventArgs e)
        {
            messageBox = new MessageBoxScreen(Game, "Are you sure you want to exit the game?" + '\n' + "All unsaved progress will be lost!" + '\n' + " ", true);
            Game.Components.Add(messageBox);
            messageBox.Accepted += ConfirmExitToMenu;
            messageBox.Cancelled += DiscardExit;

        }

        void ConfirmExitToMenu(object sender, PlayerIndexEventArgs e)
        {
            Game1.isPaused = false;
            messageBox.Dispose();
            Game.Components.Remove(messageBox);
           // sound.StopSound(sound.ThemeInstance);
            GameState.game_state.time_counter = 0.0f; //need this to stop eventual time sound
#if XBOX
            Game.Components.Remove(sharedSaveDevice);
#endif

            while (Game.Components.Count > 1)
            {
                ((GameComponent)Game.Components[1]).Dispose();
            }
            this.Dispose();

            Game.Components.Remove(this);
            Game.Components.Add(new Main_Menu(Game));

        }


        void DiscardExit(object sender, PlayerIndexEventArgs e)
        {
            messageBox.Dispose();
            Game.Components.Remove(messageBox);

        }


        /// <summary>
        /// Event handler for when the music volume menu entry is selected.
        /// </summary>
        void MusicVolumeDownEntrySelected(object sender, PlayerIndexEventArgs e)
        {
            if (Game1.musicVolume > 0)
            {
                Game1.musicVolume--;
                SetMenuEntryText();
                sound.MusicVolumeDown(Game1.musicVolume);
            }

        }

        void MusicVolumeUpEntrySelected(object sender, PlayerIndexEventArgs e)
        {
            if (Game1.musicVolume < 10)
            {
                Game1.musicVolume++;
                SetMenuEntryText();
                sound.MusicVolumeUp(Game1.musicVolume);
            }
        }

        void EffectsVolumeDownEntrySelected(object sender, PlayerIndexEventArgs e)
        {
            if (Game1.effectsVolume > 0)
            {
                Game1.effectsVolume--;
                SetMenuEntryText();
                sound.EffectsVolumeDown(Game1.effectsVolume);
            }
            sound.PlaySound(sound.HopSoundInstance);

        }

        void EffectsVolumeUpEntrySelected(object sender, PlayerIndexEventArgs e)
        {
            if (Game1.effectsVolume < 10)
            {
                Game1.effectsVolume++;
                SetMenuEntryText();
                sound.EffectsVolumeUp(Game1.effectsVolume);
            }
            sound.PlaySound(sound.HopSoundInstance);
        }


        #endregion


        /// <summary>
        /// Load graphics content
        /// </summary>
        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            background = Game.Content.Load<Texture2D>("pause_back");
        }

        //help method to change menu entries text
        void SetMenuEntryText()
        {
            musicVolumeMenuEntry.Text = "Music volume: " + Game1.musicVolume;
            effectsVolumeMenuEntry.Text = "Effects volume: " + Game1.effectsVolume;
        }

        /// <summary>
        /// Update method
        /// </summary>
        /// <param name="gameTime">Time of the game.</param>
        public override void Update(GameTime gameTime)
        {
            input.Update();
            PlayerIndex playerIndex = PlayerIndex.One;

            if (ib.menuLeft.Evaluate(input, null, out playerIndex))
            {
                if (selectedEntry == 3)
                {
                    selectedArrow = 0;
                    menuArrows[selectedArrow].OnSelectEntry(playerIndex);
                }
                if (selectedEntry == 4)
                {
                    selectedArrow = 2;
                    menuArrows[selectedArrow].OnSelectEntry(playerIndex);
                }
            }

            if (ib.menuRight.Evaluate(input, null, out playerIndex))
            {
                if (selectedEntry == 3)
                {
                    selectedArrow = 1;
                    menuArrows[selectedArrow].OnSelectEntry(playerIndex);
                }
                if (selectedEntry == 4)
                {
                    selectedArrow = 3;
                    menuArrows[selectedArrow].OnSelectEntry(playerIndex);
                }
            }


            if (ib.menuUp.Evaluate(input, null, out playerIndex))
            {
                selectedEntry--;
                if (selectedEntry < 0)
                    selectedEntry = menuEntries.Count - 1;
            }

            // Move to the next menu entry?
            if (ib.menuDown.Evaluate(input, null, out playerIndex))
            {
                selectedEntry++;

                if (selectedEntry >= menuEntries.Count)
                    selectedEntry = 0;
            }

            if (ib.menuSelect.Evaluate(input, null, out playerIndex))
            {
                menuEntries[selectedEntry].OnSelectEntry(playerIndex);
            }
         
            for (int i = 0; i < menuEntries.Count; i++)
            {
                bool isSelected = (i == selectedEntry);

                menuEntries[i].Update(isSelected, gameTime);
            }

            for (int i = 0; i < menuArrows.Count; i++)
            {
                bool isSelected = (i == selectedArrow);

                menuArrows[i].Update(isSelected, gameTime);
            }


            base.Update(gameTime);
        }


        public override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);

            var height = GraphicsDevice.Viewport.Height;

            Vector2 position = new Vector2(0f, 370 * (float)height / 1080.0f);

            // update each menu entry's location in turn
            for (int i = 0; i < menuEntries.Count; i++)
            {
                MenuEntry menuEntry = menuEntries[i];

                // each entry is to be centered horizontally
                position.X = GraphicsDevice.Viewport.Width / 2 - menuEntry.GetWidth() / 2;

                 // set the entry's position
                menuEntry.Position = position;

                // move down for the next entry
                position.Y += 100 * (float)height / 1080.0f;
            }
            minMusicVolume.Position = musicVolumeMenuEntry.Position - (new Vector2(30.0f, 0.0f));
            maxMusicVolume.Position = musicVolumeMenuEntry.Position + (new Vector2(musicVolumeMenuEntry.GetWidth() + 30.0f, 0.0f));
            minEffectsVolume.Position = effectsVolumeMenuEntry.Position - (new Vector2(30.0f, 0.0f));
            maxEffectsVolume.Position = effectsVolumeMenuEntry.Position + (new Vector2(effectsVolumeMenuEntry.GetWidth() + 30.0f, 0.0f));
            spriteBatch.Begin();
            
            spriteBatch.Draw(background, new Rectangle(0, 0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height), new Rectangle(0, 0, background.Width, background.Height), Color.White, 0.0f, Vector2.Zero, SpriteEffects.None, 0);

            // Draw each menu entry in turn.
            for (int i = 0; i < menuArrows.Count; i++)
            {
                MenuEntry menuEntry = menuArrows[i];

                bool isSelected = (i == selectedArrow);

                //Need this check to scale down the font size for very low resolutions
                //Bad solution, but better than nothing
                   if (GraphicsDevice.Viewport.Width > 600)
                    menuEntry.Draw(isSelected, gameTime, spriteBatch, font,1.0f);
                else
                    menuEntry.Draw(isSelected, gameTime, spriteBatch, font,0.5f);
            }


            // Draw each menu entry in turn.
            for (int i = 0; i < menuEntries.Count; i++)
            {
                MenuEntry menuEntry = menuEntries[i];


                bool isSelected = (i == selectedEntry);

                //Need this check to scale down the font size for very low resolutions
                //Bad solution, but better than nothing
                  if (GraphicsDevice.Viewport.Width > 600)
                    menuEntry.Draw(isSelected, gameTime, spriteBatch, font,1.0f);
                else
                    menuEntry.Draw(isSelected, gameTime, spriteBatch, font,0.5f);
            }
            spriteBatch.End();
            base.Draw(gameTime);
        }
    }
}
